package com.frank.loadinglibrary.special;

import com.frank.loadinglibrary.common.BaseLoadingComponent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

/**
 * @author SUQI
 * @date 2021/5/11
 * @description 小球弹跳动画
 **/
public class BallJumpLoadingComponent extends BaseLoadingComponent<BallJumpLoadingComponent> implements Component.DrawTask {

    private final Color[] color = {Color.WHITE, Color.YELLOW, Color.BLUE};
    private Paint mPaint;
    private Paint mTextPaint;
    private float radius = 40f;
    private Shape mShape = Shape.TRIANGLE;
    private Path mPath;
    private Path mTextPath;
    private float moveY = 0;
    private float rotateAngle = 0;
    private AnimatorValue animatorValue;

    private int PAINT_TEXTSIZE = 30;
    private final int PAINT_TEXT_BASEIINE = PAINT_TEXTSIZE;//BASELINE的高度
    private String mResText;//画出来的文字
    private int mTextWidth;//文字的宽度
    private String mDefaultText;
    private final int DEFAULT_RECF_SPACE = 6;//默认的画弧形的时候的间距,值越大速度越快，不能超过最大值
    private final int MAX_RECF_SPACE = 12;//最大的画弧形的时候的间距
    private final int MIN_RECF_SPACE = -12;//最大的画弧形的时候的间距
    private int mRecfSpace = 0;//矩形RECF间距
    private final int STATUS_DOWN_CURVE = 0;//向下弯曲的状态
    private final int STATUS_UP_CURVE = 1;//向上恢复的状态
    private final int STATUS_FLAT_CURVE = 2;//平的状态
    private int mCurveStatus = STATUS_FLAT_CURVE;
    private final int MAX_SPRING_COUNT = 10;//来回弹动的时间
    private int mSringCount = MAX_SPRING_COUNT;//当前弹动的次数


    public BallJumpLoadingComponent(Context context) {
        this(context, null);
    }

    public BallJumpLoadingComponent(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public BallJumpLoadingComponent(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
        addDrawTask(this);
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                startAnimators();
                HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "onComponentBoundToWindow");
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        });
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_STYLE);

        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL_STYLE);

        mPath = new Path();
        mTextPath = new Path();

        mDefaultText = "正在加载。。。";
        mResText = mDefaultText;
        mTextPaint = new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(PAINT_TEXTSIZE);
        mTextPaint.setStyle(Paint.Style.STROKE_STYLE);
        mTextPaint.setTextAlign(TextAlignment.LEFT);
        mTextWidth = (int) mTextPaint.measureText(mResText);
    }

    @Override
    protected void stopAnimators() {
        if (animatorValue != null) {
            animatorValue.cancel();
            animatorValue.end();
        }
    }

    @Override
    protected void startAnimators() {
        HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "startAnimators");
        animatorValue = new AnimatorValue();
        animatorValue.setDuration(1000);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "moveY = " + moveY + " Angle = " + rotateAngle);
            moveY = (v > 0.5 ? 1 - v : v) * 3 * radius;
            rotateAngle = 360 * v;
            invalidate();
        });
        animatorValue.setLoopedListener(animator -> changeShapeAndBendingText());
        animatorValue.start();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.save();
        switch (mShape) {
            case TRIANGLE:
                canvas.rotate(rotateAngle, getWidth() * 0.5f, getHeight() * 0.5f - moveY - radius * (float) Math.tan(Math.toRadians(30)));
                mPaint.setColor(color[0]);
                mPath.reset();
                mPath.moveTo(getWidth() * 0.5f, getHeight() * 0.5f - moveY - 2 * radius * (float) Math.sin(Math.toRadians(60)));
                HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "x = " + getWidth() * 0.5f + "  y = " + (getHeight() * 0.5f - moveY - 2 * radius * (float) Math.sin(Math.toRadians(60))));
                mPath.lineTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY);
                HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "x = " + (getWidth() * 0.5f - radius) + "  y = " + (getHeight() * 0.5f - moveY));
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY);
                HiLog.debug(new HiLogLabel(HiLog.DEBUG, 1, "animatorValue1"), "x = " + (getWidth() * 0.5f + radius) + "  y = " + (getHeight() * 0.5f - moveY));
                mPath.close();
                canvas.drawPath(mPath, mPaint);
                break;
            case CIRCLE:
                mPaint.setColor(color[1]);
                mPath.reset();
                canvas.drawCircle(getWidth() * 0.5f, getHeight() * 0.5f - moveY, radius, mPaint);
                break;
            case RECT:
                canvas.rotate(rotateAngle, getWidth() * 0.5f, getHeight() * 0.5f - moveY);
                mPaint.setColor(color[2]);
                mPath.reset();
                mPath.moveTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY + radius);
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY + radius);
                mPath.lineTo(getWidth() * 0.5f + radius, getHeight() * 0.5f - moveY - radius);
                mPath.lineTo(getWidth() * 0.5f - radius, getHeight() * 0.5f - moveY - radius);
                mPath.close();
                canvas.drawPath(mPath, mPaint);
                break;
        }
        canvas.restore();
        drawLoadingText(canvas);

    }

    private void changeShapeAndBendingText() {
        switch (mShape) {
            case TRIANGLE:
                mShape = Shape.CIRCLE;
                break;
            case CIRCLE:
                mShape = Shape.RECT;
                break;
            case RECT:
                mShape = Shape.TRIANGLE;
                break;
        }
        mSringCount = 0;
        mCurveStatus = STATUS_DOWN_CURVE;
    }

    public enum Shape {
        TRIANGLE, RECT, CIRCLE
    }

    private void drawLoadingText(Canvas canvas) {
        drawArcPath();
        mRecfSpace = getRecfSpace();
        if (mRecfSpace >= MAX_RECF_SPACE) {
            mCurveStatus = STATUS_UP_CURVE;
        } else if (mRecfSpace <= MIN_RECF_SPACE) {
            mCurveStatus = STATUS_DOWN_CURVE;
        }
        if (mSringCount < MAX_SPRING_COUNT) {
            mSringCount++;
            invalidate();
        } else {
            reset(canvas);
        }
        canvas.drawTextOnPath(mTextPaint, mResText, mTextPath, 0, 0);
    }

    void reset(Canvas canvas) {
        mRecfSpace = 0;
        drawArcPath();
        mCurveStatus = STATUS_FLAT_CURVE;

    }

    /**
     * 当矩形间距这块如果到了最大弯曲值就
     * 每次递减，反之则递增，平行状态不变
     *
     * @return
     */
    int getRecfSpace() {
        if (mCurveStatus == STATUS_DOWN_CURVE) {
            return mRecfSpace + DEFAULT_RECF_SPACE;
        } else if (mCurveStatus == STATUS_UP_CURVE) {
            return mRecfSpace - DEFAULT_RECF_SPACE;
        } else {
            return 0;
        }
    }


    /**
     * +
     * 画出弧线路径
     */
    void drawArcPath() {
        mTextPath.reset();
        mTextPath.moveTo((getWidth() - mTextWidth) / 2f, getHeight() / 2f + PAINT_TEXT_BASEIINE + radius); //设定起始点
        mTextPath.cubicTo(getWidth() / 2f - mTextWidth / 3f, getHeight() / 2f + PAINT_TEXT_BASEIINE + radius + mRecfSpace,
                getWidth() / 2f + mTextWidth / 3f, getHeight() / 2f + PAINT_TEXT_BASEIINE + radius + mRecfSpace,
                (getWidth() + mTextWidth) / 2f, getHeight() / 2f + PAINT_TEXT_BASEIINE + radius);
        mTextPath.close();
    }
}
